(function() {

    var
    $u = juliet.using({
        validationResult : 'juliet.validation.validationResult',
        uidGenerator : 'juliet.core.uidGenerator-0.1',
        i18n : 'juliet.i18n.i18n-0.1',
        ValidatorsChain : 'juliet.validation.ValidatorsChain-0.1',
        validatorMetadataUpdater : 'juliet.validation.validatorMetadataUpdater',
        Observer : 'juliet.core.Observer-0.1'
    }),
    vr = $u('validationResult'),
    $ = juliet.jQuery;

    /**
     * Manage fields validation process
     */
    var ValidationManagerClass = function() {

        this.result = vr.UNKNOWN;
        this.detailedResult = vr.UNKNOWN;
        this.chains = { };
        this.errorOutputContainerSelector = null;
        this.locale = 'ru';
        this.observer = juliet.createObject($u('Observer'));

        this.initialize = function(o, errorOutputContainerSelector) {
            this.errorOutputContainerSelector = errorOutputContainerSelector;
            this.addChains(o);
        };

        this.addChains = function(o) {
            var newChains = { };

            for (var i = 0; i < o.length; ++i) {
                var newChain = this.addChain(o[i]);
                newChains[newChain.uid] = newChain;
            }

            $u('validatorMetadataUpdater').run(newChains);
        };

        this.addChain = function(o) {
            var newChain = juliet.createObject($u('ValidatorsChain'), {
                uid : o.uid || $u('uidGenerator').getUid(),
                manager : this,
                metadata : o
            });

            newChain.observer.subscribe('validated', this.chainEventHandler, this);
            newChain.observer.subscribe('reseted', this.chainEventHandler, this);

            this.chains[newChain.uid] = newChain;
            return newChain;
        };

        this.chainEventHandler = function() {
            this.updateValidationResult();
            if (this.result == vr.SUCCESS) this.hideLastError();
        };

        this.validate = function() {
            var chainUid;

            for (chainUid in this.chains) {
                var chain = this.chains[chainUid];
                if (chain.active) chain.validate({ callFromManager : true });
            }

            this.updateValidationResult();
            this.showLastError();

            return this.result;
        };

        this.updateValidationResult = function() {
            var chainUid, result = 0;

            for (chainUid in this.chains) {
                var chain = this.chains[chainUid];
                if (chain.active) result |= chain.result;
            }

            this.detailedResult = result;
            this.result = vr.simplifyResult(result);

            this.observer.notify('result-updated', this.result);
        };

        this.setChainActivity = function(chainUid, active) {
            var chain = this.chains[chainUid];
            chain.reset();
            chain.active = active;
            chain.stopInProgressValidator();
        };

        this.getErrorOutputElement = function(field) {
            var errorOutputContainer = null;

            if (field) errorOutputContainer = field.next('.information');
            else errorOutputContainer = $(this.errorOutputContainerSelector);

            var errorOutput = errorOutputContainer.find('.error');

            if (errorOutput.length == 0) {
                errorOutput = $('<span class="error" />');
                errorOutputContainer.prepend(errorOutput);
            }

            return errorOutput;
        };

        this.showLastError = function() {
            if ((this.detailedResult & vr.FAILED) != vr.FAILED) return;
            var text = $u('i18n').get('validation:form.summary');
            this.getErrorOutputElement().text(text);
        };

        this.hideLastError = function() {
            this.getErrorOutputElement().text('');
        };

    };

    juliet.registerModule('juliet.validation', 'ValidationManager-0.1', ValidationManagerClass);

})();
